package br.com.fumec.maze;

import java.io.ByteArrayInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import br.com.fumec.util.MazeConnection;
import br.com.fumec.util.Movements;

public class Problema {
	private String url;
	private MazeConnection connection;
	
	private No origem;
	private No destino;
	
	public No getOrigem(){
		return this.origem;
	}
	
	public Problema() throws Exception{
		this("http://localhost:7890/endpoint");
	}
	
	public Problema(String url) throws Exception{
		this.url = url;
	    this.connection = new MazeConnection();
	    
	    State state = this.getCurrentState();
	    this.origem = new No(state.getPosition().getX(), state.getPosition().getY(), state.getMoves().getMovements());
	    this.destino = new No(state.getObjective().getX(), state.getObjective().getY(), state.getMoves().getMovements());
	}
	
	public double getDistance(No origem){
		return Math.sqrt(Math.pow(origem.getX() - this.destino.getX(), 2) + Math.pow(origem.getY() - this.destino.getY(), 2));
	}
	
	public Element string2DocElement(String xml) throws Exception{
		ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes());
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(stream);
        return doc.getDocumentElement();
	}
	
	public State getCurrentState() throws Exception{
		return State.newInstance(this.string2DocElement(this.connection.getState(this.url)));
	}
	
	public Moves getMoves() throws Exception{
		return this.getCurrentState().getMoves();
	}
	
	public void move(Movements m) throws Exception{
		this.connection.move(this.url, m);
	}
	
	public boolean isObjective(No current){
		return current.getX() == this.destino.getX() && current.getY() == this.destino.getY();
	}
	
	public No getNextStep(No current) throws Exception{
		No bestStep = null;
		Movements[] movements = current.getMovimentos();
		for(int i = 0; i < movements.length; i++){
			if(movements[i] == Movements.LEFT){
				No temp = new No(current.getX()-1, current.getY(), current.getMovimentos());
				if(bestStep == null || this.getDistance(bestStep) > this.getDistance(temp)){
					temp.setMovimento(Movements.LEFT);
					bestStep = temp;
				}
			}
			
			if(movements[i] == Movements.RIGHT){
				No temp = new No(current.getX()+1, current.getY(), current.getMovimentos());
				if(bestStep == null || this.getDistance(bestStep) > this.getDistance(temp)){
					temp.setMovimento(Movements.RIGHT);
					bestStep = temp;
				}
			}
			
			if(movements[i] == Movements.UP){
				No temp = new No(current.getX(), current.getY()-1, current.getMovimentos());
				if(bestStep == null || this.getDistance(bestStep) > this.getDistance(temp)){
					temp.setMovimento(Movements.UP);
					bestStep = temp;
				}
			}
			
			if(movements[i] == Movements.DOWN){
				No temp = new No(current.getX(), current.getY()+1, current.getMovimentos());
				if(bestStep == null || this.getDistance(bestStep) > this.getDistance(temp)){
					temp.setMovimento(Movements.DOWN);
					bestStep = temp;
				}
			}
		}
		return bestStep;
	}
	
	public Movements getReverseMovement(Movements movement){
		if(movement == Movements.LEFT){
			return Movements.RIGHT;
		}
		
		if(movement == Movements.RIGHT){
			return Movements.LEFT;
		}
		
		if(movement == Movements.UP){
			return Movements.DOWN;
		}
		
		if(movement == Movements.DOWN){
			return Movements.UP;
		}
		return null;
	}
}